from typing import List, Union, Optional

from functional import seq
from pydantic import BaseModel, Field, root_validator

from odoo.addons.basic_configuration.functions.rp_sequence_code_fc import RPSequenceCode
from ..step.step_level import AvailableValueAdded
from .sec_level import Customer, PostCode, Parcel, MailRoute, Aging, HeadTailFulfillment, ShipValueAdded, \
    RpShipmentValueAdded, ContactUsType, SuggestedReadingTime, WebArticleCategory, WebArticleIndustry, WebArticleTag, \
    RpQuestionAnswerLevel, RpQuestionAndAnswerType
from .trd_level import Country, PackageType, Currency, Date, State, City, UomUom, Shipper, RpCourierPostalOutlet, \
    RPSalePriceAdjust, DateTime

"""
登录注册
"""


class Token(BaseModel):
    """ 返回给用户的token """
    access_token: str = Field(..., description='令牌')
    token_type: str = Field(default='Bearer', description='类型')


class UserRegistration(BaseModel):
    """用户注册信息"""
    first_name: str = Field(..., description='名')
    last_name: str = Field(..., description='姓')
    email: str = Field(..., description='邮箱')
    password: str = Field(..., description='密码')


class UserFindPassword(BaseModel):
    """用户注册信息"""
    email: str = Field(..., description='邮箱')
    verify_code: str = Field(..., description='验证码')
    password: str = Field(..., description='密码')
    sure_password: str = Field(..., description='确认密码')


class RpShipment(BaseModel):
    """
    对应【rp.shipment】运输单
    """
    code: str = Field(None, description='运输单号')
    weight_uom_id: UomUom = Field(None, description='重量单位')
    volume_uom_id: UomUom = Field(None, description='体积单位')
    currency_id: Currency = Field(None, description='货币单位')
    state: str = Field(None, description='状态')
    customer_id: Customer = Field(None, description='客户')
    # 发件信息
    send_postal_code: PostCode = Field(None, description='发件邮编')
    send_street: str = Field(None, description='发件街道')
    send_first_name: str = Field(None, description='发件名')
    send_last_name: str = Field(None, description='发件姓')
    send_phone: str = Field(None, description='发件电话')
    send_address_type: str = Field(None, description='发件地址类型')
    send_company_name: str = Field(None, description='发件公司名称')
    # 收件信息
    receive_postal_code: PostCode = Field(None, description='收件邮编')
    receive_street: str = Field(None, description='收件街道')
    receive_first_name: str = Field(None, description='收件名')
    receive_last_name: str = Field(None, description='收件姓')
    receive_phone: str = Field(None, description='收件电话')
    receive_address_type: str = Field(None, description='收件地址类型')
    receive_company_name: str = Field(None, description='收件公司名称')
    # 托运商信息
    shipper_id: Shipper = Field(None, description='托运商')
    shipper_mail_route_id: MailRoute = Field(None, description='托运商邮路')
    package_type_id: PackageType = Field(None, description='包裹类型')
    aging_id: Aging = Field(None, description='时效')
    # 头尾程信息
    pickup_flag: bool = Field(None, description='上门取件')
    dropoff_flag: bool = Field(None, description='网点收件')
    delivery_flag: bool = Field(None, description='送货上门')
    collect_flag: bool = Field(None, description='网点取件')
    head_postal_outlet_id: RpCourierPostalOutlet = Field(None, description='头程网点')
    tail_postal_outlet_id: RpCourierPostalOutlet = Field(None, description='尾程网点')
    # TODO 预约上门取件
    rp_parcel_ids: List[Parcel] = Field(None, description='包裹')
    parcel_total_weight: float = Field(None, description='包裹总重量')
    parcel_total_volume: float = Field(None, description='包裹总体积')
    parcel_total_values: float = Field(None, description='包裹总价值')
    parcel_actual_weight: float = Field(None, description='包裹实际重量')
    parcel_rounded_weight: float = Field(None, description='包裹取整重量')
    rp_shipment_value_added_line_ids: List[RpShipmentValueAdded] = Field(None, description='增值服务明细')
    mail_route_price: float = Field(..., description='邮路价格')
    fulfillment_price: float = Field(..., description='头尾程价格')
    value_added_price: float = Field(..., description='增值服务价格')
    total_price: float = Field(..., description='总价格')
    label_picture_ids: List[str] = Field(..., description='面单图片')
    remarks: str = Field(..., description='备注')

    @root_validator(pre=True)
    def create(cls, values):
        mdl = values.get('__from_odoo')
        env = values.get('__env')
        if mdl and env:
            values['id'] = mdl.id
            values['code'] = mdl.code
            values['weight_uom_id'] = UomUom(__from_odoo=mdl.weight_uom_id, __env=env)
            values['volume_uom_id'] = UomUom(__from_odoo=mdl.volume_uom_id, __env=env)
            values['currency_id'] = UomUom(__from_odoo=mdl.currency_id, __env=env)
            values['state'] = mdl.state
            values['customer_id'] = Customer(__from_odoo=mdl.customer_id, __env=env)
            values['send_postal_code'] = PostCode(__from_odoo=mdl.send_postal_code_id, __env=env)
            values['send_street'] = mdl.send_street
            values['send_first_name'] = mdl.send_first_name
            values['send_last_name'] = mdl.send_last_name
            values['send_phone'] = mdl.send_phone
            values['send_address_type'] = mdl.send_address_type
            values['send_company_name'] = mdl.send_company_name
            values['receive_postal_code'] = PostCode(__from_odoo=mdl.receive_postal_code_id, __env=env)
            values['receive_street'] = mdl.receive_street
            values['receive_first_name'] = mdl.receive_first_name
            values['receive_last_name'] = mdl.receive_last_name
            values['receive_phone'] = mdl.receive_phone
            values['receive_address_type'] = mdl.receive_address_type
            values['receive_company_name'] = mdl.receive_company_name
            values['shipper_id'] = Shipper(__from_odoo=mdl.shipper_id, __env=env)
            values['shipper_mail_route_id'] = MailRoute(__from_odoo=mdl.shipper_mail_route_id, __env=env)
            values['package_type_id'] = PackageType(__from_odoo=mdl.package_type_id, __env=env)
            values['aging_id'] = Aging(__from_odoo=mdl.aging_id, __env=env)
            values['pickup_flag'] = mdl.pickup_flag
            values['dropoff_flag'] = mdl.dropoff_flag
            values['delivery_flag'] = mdl.delivery_flag
            values['collect_flag'] = mdl.collect_flag
            values['head_postal_outlet_id'] = RpCourierPostalOutlet(__from_odoo=mdl.head_postal_outlet_id, __env=env)
            values['tail_postal_outlet_id'] = RpCourierPostalOutlet(__from_odoo=mdl.tail_postal_outlet_id, __env=env)
            values['rp_parcel_ids'] = [Parcel(__from_odoo=record, __env=env) for record in mdl.rp_parcel_ids]
            values['parcel_total_weight'] = mdl.parcel_total_weight
            values['parcel_total_volume'] = mdl.parcel_total_volume
            values['parcel_total_values'] = mdl.parcel_total_values
            values['parcel_actual_weight'] = mdl.parcel_actual_weight
            values['parcel_rounded_weight'] = mdl.parcel_rounded_weight
            values['rp_shipment_value_added_line_ids'] = [RpShipmentValueAdded(__from_odoo=record, __env=env) for record
                                                          in mdl.rp_shipment_value_added_line_ids]
            values['mail_route_price'] = mdl.mail_route_price
            values['fulfillment_price'] = mdl.fulfillment_price
            values['value_added_price'] = mdl.value_added_price
            values['total_price'] = mdl.total_price
            values['label_picture_ids'] = seq(mdl.label_picture_ids).map(
                lambda r: f'http://admin.rectaparcel.com/web/image?model=rp.shipment&id={r.id}&field=photo').to_list()
            values['remarks'] = mdl.remarks
        return values


class RpShipOrder(BaseModel):
    """
    对应【rp.ship.order】运输订单
    """
    # step 1
    id: int = Field(None, description='订单ID')
    code: str = Field(None, description='订单单号')
    state: str = Field(None, description='状态')
    customer_id: Customer = Field(None, description='客户')
    send_postal_code: PostCode = Field(None, description='发件邮编')
    receive_postal_code: PostCode = Field(None, description='收件邮编')
    package_type_id: PackageType = Field(None, description='包裹类型')
    # step 2
    rp_package_list: List[Parcel] = Field(None, description='包裹列表')
    parcel_total_weight: float = Field(None, description='包裹总重量')
    parcel_total_volume: float = Field(None, description='包裹总体积')
    parcel_total_values: float = Field(None, description='包裹总价值')
    parcel_actual_weight: float = Field(None, description='包裹实际重量')
    parcel_rounded_weight: float = Field(None, description='包裹取整重量')
    currency_id: Currency = Field(None, description='货币单位')
    # step 3
    shipper_mail_route: MailRoute = Field(None, description='托运商邮路')
    expect_arrive_date: str = Field(None, description='预计到达时间')
    aging_id: Aging = Field(None, description='时效')
    used_sale_price_adjust_ids: List[RPSalePriceAdjust] = Field(None, description='邮路使用销售调价')
    available_value_added_list: List[AvailableValueAdded] = Field(None, description='该邮路可用的增值服务(这里需要在外部逻辑添加)')
    # step 4
    rp_ship_order_fulfillment_list: List[HeadTailFulfillment] = Field(None, description='头尾程明细')
    value_added_list: List[ShipValueAdded] = Field(None, description='增值服务明细')
    # step 5
    send_email: str = Field(None, description='发件人邮箱')
    send_street: str = Field(None, description='发件街道1')
    send_street2: str = Field(None, description='发件街道2')
    send_first_name: str = Field(None, description='发件名')
    send_last_name: str = Field(None, description='发件姓')
    send_phone: str = Field(None, description='发件电话')
    send_phone_areacode: str = Field(None, description='发件电话区号')
    send_address_type: str = Field(None, description='发件地址类型')
    send_company_name: str = Field(None, description='发送公司名称')
    receive_email: str = Field(None, description='收件人邮箱')
    receive_street: str = Field(None, description='收件街道1')
    receive_street2: str = Field(None, description='收件街道2')
    receive_first_name: str = Field(None, description='收件名')
    receive_last_name: str = Field(None, description='收件姓')
    receive_phone: str = Field(None, description='收件电话')
    receive_phone_areacode: str = Field(None, description='收件电话区号')
    receive_address_type: str = Field(None, description='收件地址')
    receive_company_name: str = Field(..., description='收件公司')
    invoice_receive_street: str = Field(None, description='发票接收地址1')
    invoice_receive_street2: str = Field(None, description='发票接收地址2')
    invoice_first_name: str = Field(None, description='发票接收人名')
    invoice_last_name: str = Field(None, description='发票接收人姓')
    invoice_phone_number: str = Field(None, description='发票接收人电话')
    invoice_phone_areacode: str = Field(None, description='发票接收人电话区号')
    invoice_address_type: str = Field(None, description='发票接收地址')
    invoice_email: str = Field(None, description='发票邮箱')
    invoice_company_name: str = Field(None, description='发票邮寄地址公司名称')
    copy_from_sender: bool = Field(None, description='从发件复制')
    notification_email: str = Field(None, description='提醒邮箱')
    # step 6
    mail_route_actual_price: float = Field(None, description='邮路实价')
    fulfillment_total_actual_price: float = Field(None, description='头尾城实价')
    value_added_total_actual_price: float = Field(None, description='增值服务二类实价')
    total_actual_price: float = Field(None, description='总实价')
    shipment_id: List['RpShipment'] = Field(None, description='运输单')
    shipment_number: int = Field(None, description='运输单数量')
    remarks: str = Field(None, description='备注')

    @root_validator(pre=True)
    def create(cls, values):
        mdl = values.get('__from_odoo')
        env = values.get('__env')
        if mdl and env:
            values['id'] = mdl.id
            values['code'] = mdl.code
            values['state'] = mdl.state
            values['customer_id'] = Customer(__from_odoo=mdl.customer_id, __env=env)
            values['send_postal_code'] = PostCode(__from_odoo=mdl.send_postal_code_id, __env=env)
            values['receive_postal_code'] = PostCode(__from_odoo=mdl.receive_postal_code_id, __env=env)
            values['package_type_id'] = PackageType(__from_odoo=mdl.package_type_id, __env=env)
            values['parcel_total_weight'] = mdl.parcel_total_weight
            values['parcel_total_volume'] = mdl.parcel_total_volume
            values['parcel_total_values'] = mdl.parcel_total_values
            values['currency_id'] = Currency(__from_odoo=mdl.currency_id, __env=env)
            values['parcel_actual_weight'] = mdl.parcel_actual_weight
            values['parcel_rounded_weight'] = mdl.parcel_rounded_weight
            values['rp_package_list'] = [Parcel(__from_odoo=record, __env=env) for record in mdl.rp_parcel_ids]
            values['shipper_mail_route'] = MailRoute(__from_odoo=mdl.shipper_mail_route_id, __env=env)
            values['expect_arrive_date'] = mdl.expect_arrive_date.strftime(
                "%Y-%m-%d %H:%M:%S") if mdl.expect_arrive_date else False
            values['aging_id'] = Aging(__from_odoo=mdl.aging_id, __env=env)
            values['rp_ship_order_fulfillment_list'] = [HeadTailFulfillment(__from_odoo=record, __env=env) for record in
                                                        mdl.rp_ship_order_fulfillment_line_ids]
            values['value_added_list'] = [ShipValueAdded(__from_odoo=record, __env=env) for record in
                                          mdl.rp_ship_order_value_added_line_ids]
            values['notification_email'] = mdl.email
            values['send_email'] = mdl.send_email
            values['send_street'] = mdl.send_street
            values['send_street2'] = mdl.send_street2
            values['send_first_name'] = mdl.send_first_name
            values['send_last_name'] = mdl.send_last_name
            values['send_phone'] = mdl.send_phone
            values['send_phone_areacode'] = mdl.send_phone_areacode
            values['send_address_type'] = mdl.send_address_type
            values['send_company_name'] = mdl.send_company_name
            values['receive_email'] = mdl.receive_email
            values['receive_street'] = mdl.receive_street
            values['receive_street2'] = mdl.receive_street2
            values['receive_first_name'] = mdl.receive_first_name
            values['receive_last_name'] = mdl.receive_last_name
            values['receive_phone'] = mdl.receive_phone
            values['receive_phone_areacode'] = mdl.receive_phone_areacode
            values['receive_address_type'] = mdl.receive_address_type
            values['receive_company_name'] = mdl.receive_company_name
            values['invoice_receive_street'] = mdl.invoice_receive_street
            values['invoice_receive_street2'] = mdl.invoice_receive_street2
            values['invoice_first_name'] = mdl.invoice_first_name
            values['invoice_last_name'] = mdl.invoice_last_name
            values['invoice_email'] = mdl.invoice_email
            values['invoice_phone_number'] = mdl.invoice_phone_number
            values['invoice_phone_areacode'] = mdl.invoice_phone_areacode
            values['invoice_address_type'] = mdl.invoice_address_type
            values['invoice_company_name'] = mdl.invoice_company_name
            values['copy_from_sender'] = mdl.copy_from_sender
            values['mail_route_actual_price'] = mdl.mail_route_actual_price
            values['fulfillment_total_actual_price'] = mdl.fulfillment_total_actual_price
            values['value_added_total_actual_price'] = mdl.value_added_total_actual_price
            values['total_actual_price'] = mdl.total_actual_price
            values['shipment_id'] = [RpShipment(__from_odoo=record, __env=env) for record in mdl.shipment_ids]
            values['shipment_number'] = mdl.shipment_number
            values['remarks'] = mdl.remarks
        return values


"""
网站管理Reference Model
"""


class WebSubscription(BaseModel):
    """
    订阅我们
    """
    email: str = Field(..., description='邮箱',
                       pattern=r'^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$',
                       example='palmnetqd@163.com')

    def to_odoo(self, env):
        """ 创建pe.web.subscription对象 """
        rcd = env['rp.web.subscription'].create({'email': self.email})
        return rcd


class ContactUs(BaseModel):
    """
    联系我们
    """
    first_name: Optional[str] = Field(None, description='名')
    last_name: Optional[str] = Field(None, description='名')
    email: Optional[str] = Field(None, description='邮箱',
                                 pattern=r'^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$',
                                 example='palmnetqd@163.com')
    phone: Optional[str] = Field(None, description='电话')
    type: ContactUsType = Field(..., description='类型')
    body: str = Field(..., description='内容')

    def to_odoo(self, env):
        """ 创建pe.web.contact.us对象 """
        rcd = env['rp.web.contact.us'].create({'first_name': self.first_name,
                                               'last_name': self.last_name,
                                               'email': self.email,
                                               'phone': self.phone,
                                               'type_id': self.type.id,
                                               'body': self.body})
        return rcd


class WebArticleList(BaseModel):
    """
    文章信息列表
    """
    code: str = Field(..., description='索引码', example='PE_AT_20240318_003')
    publication_d: Date = Field(..., description='发布时间')

    title: str = Field(..., description='标题')
    subtitle: str = Field(..., description='副标题')
    introduction: str = Field(..., description='简介')
    suggested_reading_time: SuggestedReadingTime = Field(..., description='建议阅读时间')
    cover_image: List[str] = Field(None, description='封面图')
    category: WebArticleCategory = Field(..., description='分类')
    industry: WebArticleIndustry = Field(..., description='行业')
    tags: List[WebArticleTag] = Field(..., description='标签')

    top_flag: bool = Field(False, description='置顶')

    @root_validator(pre=True)
    def create(cls, values):
        """ 传入pe.web.article的记录 """
        mdl = values.get('__from_odoo')
        env = values.get('__env')
        if mdl and env:
            values['code'] = RPSequenceCode(env).clean_serial(mdl.code)
            values['publication_d'] = Date(stamp_format=int(mdl.publication_datetime.timestamp()))

            values['title'] = mdl.title
            values['subtitle'] = mdl.subtitle
            values['introduction'] = mdl.introduction
            values['suggested_reading_time'] = SuggestedReadingTime(__from_odoo=mdl.suggested_reading_time_id,
                                                                    __env=env)
            values['cover_image'] = mdl.cover_image_ids.mapped(lambda r: r.url)
            values['category'] = WebArticleCategory(__from_odoo=mdl.category_id, __env=env)
            values['industry'] = WebArticleIndustry(__from_odoo=mdl.industry_id, __env=env)
            values['tags'] = [WebArticleTag(__from_odoo=tag, __env=env) for tag in mdl.tag_ids]

            values['top_flag'] = mdl.top_flag
        return values


class WebArticleDetail(WebArticleList):
    """
    文章信息详情
    """
    user: str = Field(..., description='发布人')
    head_image: List[str] = Field(None, description='头部图')
    body: str = Field(..., description='内容')

    relevance_article: List[str] = Field(None, description='关联文章', example='["PE_WR_20240202_002"]')

    @root_validator(pre=True)
    def create(cls, values):
        """ 传入pe.web.article的记录 """
        values = super().create(values)  # 调用父类的create方法
        mdl = values.get('__from_odoo')
        env = values.get('__env')
        if mdl and env:
            values['user'] = mdl.user_id.name
            values['head_image'] = mdl.head_image_ids.mapped(lambda r: r.url)
            values['body'] = mdl.body
            values['relevance_article'] = [RPSequenceCode(env).clean_serial(re.code) for re in
                                           mdl.relevance_article_ids]
        return values


class RpQuestionAndAnswer(BaseModel):
    level: RpQuestionAnswerLevel = Field(..., description='级别')
    type: RpQuestionAndAnswerType = Field(..., description='类型')
    question: str = Field(..., description='问题')
    answer: str = Field(..., description='回答')
    related_question_and_answer_code: List[str] = Field(None, description='关联问答', example=['RP_QNA/0002'])

    @root_validator(pre=True)
    def create(cls, values):
        """
        传入rp.question.and.answer模型记录
        """
        mdl = values.get('__from_odoo')
        env = values.get('__env')
        if mdl and env:
            values['level'] = RpQuestionAnswerLevel(__from_odoo=mdl.question_answer_level_id, __env=env)
            values['type'] = RpQuestionAndAnswerType(__from_odoo=mdl.question_answer_type_ids, __env=env)
            values['question'] = mdl.question
            values['answer'] = mdl.answer
            values['related_question_and_answer_code'] = [record.code for record in mdl.related_question_and_answer_ids]
        return values
